/**
 * @file tiny_scheduler.h
 * @author Linquan  
 * @brief 由小小调度器V2.0修改，
 *        伪线程。每个任务看作一个线程
 * @version 1.0
 * @date 2024-07-06
 * 
 * @copyright Copyright (c) 2024
 * method:
 *      1、建立时基，使用宏UpdateTimer(TaskVar)，对任务进行计时.
 *         如果要按照时间延时，需要使用__MS(time) 宏，time单位ms。
 *          TaskVar：是该任务类的实例
 * 
 *      2、使用宏 CLASS_START、CLASS_END 声明主任务类或子任务类， 
 *         其中包括必须的任务核心(默认添加)、用户自定义任务内容（也可以包括子任务实例）。
 *         类的名称也是任务的函数名，使用宏CLASS(name)指代该任务的类。
 *       
 *      3、使用宏： TaskFunStart(TaskName) 、 TaskFunEnd 进行任务函数的创建
 *          函数中使用while(1)循环运行。模拟线程。
 *        ！！！  不要忘记使用延时宏 ，否则该任务线程无法退出 ！！!
 * 
 *      4、在任务中，使用下述宏，进行延时，主动释放CPU资源。
 *         WaitX(ticks)、WaitUntil(A) 、 WaitUtilT(A,TimeOut) 
 *      
 *      5、使用宏 RunTask(TaskFunName,TaskVar) 执行任务
 *        TaskFunName：任务的函数名称
 *        TaskVar： 使用任务类创建的实例
 *    
 *      6、如果主任务中存在子任务，子任务运行需要依靠主任务的参数，
 *        在主任务中使用宏：CallSub(SubTaskFunName,SubTaskVar)调用子任务
 *        子任务类的实例是包含在主任务类中的
 *        example：strut main_class
 *          {
 *            uint8_t main_var;  // 主任务自己的参数
 *            struct SUB_class  class_var; // 子任务的参数，包含在主任务中
 *                                         // 在调用主任务时，就将这个实例传入子任务函数
 *          }
 * 
 *         
 * 
 * 
 */
#ifndef TINY_SCHEDULER_H
#define TINY_SCHEDULER_H



/* 时基配置 */
#ifndef TS_TICK_MS
#define TS_TICK_MS    10 /* ms */   
#endif

/* 是否使用信号量 */
#define TS_SEM_USED      1



/* 使用该宏，设置时间ms */
#define __MS(time)   (time/TS_TICK_MS)

#define TimeDef             unsigned short
#define LineDef             unsigned int

#ifdef TS_SEM_USED
#define SemDef              unsigned int
#endif


#define END                 ((TimeDef)-1)
#define LINE                ((__LINE__%(LineDef)-1)+1)  


#define me  (*cp)


/* 定义任务调度核心结构体 */                             
struct schedule_core
{
  TimeDef timer;
  LineDef lc;

  #if TS_SEM_USED
  SemDef  sem_count;
  #endif

};

/* 定义具体任务参数类 */
#define TS_TASK_VAR_START(TaskName)         typedef struct C##TaskName C##TaskName; \
                             TS_TaskFun(TaskName); \
                             struct C##TaskName { struct schedule_core task_core;

#define TS_TASK_VAR_END            };

/* 任务参数类，用于创建实例 */
#define TS_TASK_VAR(TaskName)          C##TaskName




/* 创建任务函数 */
#define TS_TaskFunStart(TaskName)   TimeDef TaskName(C##TaskName *cp){  _SS

#define TS_TaskFunEnd            _EE }

/* 任务函数声明 */
#define TS_TaskFun(TaskName)   TimeDef TaskName(C##TaskName *cp)


/* 开始任务 */
#define _SS                 switch(me.task_core.lc){default:
/* 结束任务 */
#define _EE                 ;}; TS_Exit;

/* 主动退出自己的任务，不再执行 */
#define TS_Exit                do { me.task_core.lc=0; return END; }  while(0)

/* 重启自己的任务，从头执行，
  注意，任务重启，任务的数据还保留！！！
*/
#define TS_Restart             do { me.task_core.lc=0; return 0; }  while(0)


/* 等待ticks 时间 */
#define TS_WaitX(ticks)        do { me.task_core.lc=LINE; return ((ticks)); case LINE:;} while(0)

/* 等待A条件满足 */
#define TS_WaitUntil(A)        do { while(!(A)) TS_WaitX(1);} while(0)

/* 等待A条件满足，超时TimeOut退出 */
#define TS_WaitUtilT(A,TimeOut, timeout_callback)                                   \
                                      do {                                          \
                                            static TimeDef _count=(TimeOut);        \
                                            do { TS_WaitX(1); _count--;             \
                                                  if(_count == 0)                   \
                                                  {                                 \
                                                    if(timeout_callback != NULL)    \
                                                    {                               \
                                                      timeout_callback();           \
                                                    }                               \
                                                  }                                 \
                                            }                                       \
                                            while((!(A))&&(_count>0));              \
                                          } while(0);


/* 更新 任务时间戳 */
#define TS_UpdateTimer(TaskVar)    do { if((TaskVar.task_core.timer!=0)&&(TaskVar.task_core.timer!=END)) TaskVar.task_core.timer--; }  while(0)

/* 运行任务 */
#define TS_RunTask(TaskFunName,TaskVar)  do { if (TaskVar.task_core.timer==0) { TimeDef d=TaskFunName(&(TaskVar)); while(TaskVar.task_core.timer!=d) TaskVar.task_core.timer=d;} }  while(0); 

/* 在任务中调用子任务 */
#define TS_CallSub(SubTaskFunName,SubTaskVar)    do { TS_WaitX(0);SubTaskVar.task_core.timer=SubTaskFunName(&(SubTaskVar));      \
                                                    if(SubTaskVar.task_core.timer!=END) return SubTaskVar.task_core.timer;} while(0)
    
/* 挂载任务 解挂任务 */
#define TS_MountTask(TaskVar)               do { TaskVar.task_core.lc=0; }  while(0)
#define TS_UNMountTask(TaskVar)             do { TaskVar.task_core.lc=END; }  while(0)



/* ******************** 信号量 ******************** */
#if TS_SEM_USED

/* 信号量初始化 */
#define TS_SEM_INIT(task_var, sem_num) (task_var).task_core.sem_count = sem_num



/* 信号量V */
#define TS_SEM_SIGNAL(task_var) ++(task_var).task_core.sem_count


/* 信号量P 信号量不存在就等待 */
#define TS_SEM_WAIT(task_var)                                  \
    do                                                         \
    {                                                          \
        TS_WaitUntil((task_var).task_core.sem_count > 0);      \
        --(task_var).task_core.sem_count;                      \
    } while (0)


/* 信号量P 信号量不存在，超时退出 */
#define TS_SEM_WAIT_TIMEOUT(task_var, timeout, timeout_callback)	    \
    do {						                                                  \
          TS_WaitUtilT((task_var).task_core.sem_count > 0,    \
                        timeout,                              \
                        timeout_callback);                    \
          --(task_var).task_core.sem_count;                           \
    } while(0)






  #endif




#endif